package com.easyexcel231130.demos.listener;


import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Slf4j
public class DemoDataListener<T> implements ReadListener<T> {
    List<T> list = new ArrayList<>();

    /**
     * 解析到每一行数据的时候调用的方法
     * 这个地方如果，没有合并单元格的话，实际上就不会读取到了，所以就不会有那么多空行的数据
     * @param t    one row value. It is same as {@link AnalysisContext#readRowHolder()}
     * @param analysisContext analysis context
     */
    @Override
    public void invoke(T t, AnalysisContext analysisContext) {
        log.info("解析到一条数据：{}", JSONObject.toJSONString(t));
        this.dataChange(t);
    }

    private void dataChange(T t) {
        // 获取excel获取的行数据
        Class<?> dataClass = t.getClass();
        // 获取字段信息
        Field[] declaredFields = dataClass.getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            //判断唯一标识，并且唯一标识的值不为空的时候，往放回结果中增加一条记录
            this.onlyflagSetData(t, field);
            //处理需要合并子项的数据
            this.processingMegerData(t, declaredFields, field);
        }
    }

    /**
     * @Description 处理需要合并子项的数据
     * @Date 11:47 2023/12/1
     * @Param [t, declaredFields, field]
     * @Return void
     **/
    private void processingMegerData(T t, Field[] declaredFields, Field field) {
        // 判断字段上是否有注解
        ExcelImportAOP excelImportAOP = field.getAnnotation(ExcelImportAOP.class);
        if (Objects.nonNull(excelImportAOP)){
            // 获取到list 的参数类型
            ParameterizedType genericType = (ParameterizedType) field.getGenericType();
            // 获取对应list泛型的class
            Class<?> actualTypeArgument = (Class<?>)genericType.getActualTypeArguments()[0];
            // 获取到泛型类型的所有字段信息
            Field[] actualDeclaredFields = actualTypeArgument.getDeclaredFields();

            try {
                // 创建泛型类型的实体对象
                Object o = actualTypeArgument.newInstance();
                // 循环泛型的字段信息
                for (Field declaredField : actualDeclaredFields) {
                    declaredField.setAccessible(true);
                    ExcelProperty excelProperty = declaredField.getAnnotation(ExcelProperty.class);
                    if (Objects.nonNull(excelProperty)){
                        String string = JSONObject.toJSONString(excelProperty.value());
                        // 循环原本的字段，如果设置的excel标题名称一致就赋值
                        for (Field declaredField1 : declaredFields) {
                            declaredField1.setAccessible(true);
                            ExcelProperty annotation = declaredField1.getAnnotation(ExcelProperty.class);
                            if (Objects.nonNull(annotation)){
                                String string1 = JSONObject.toJSONString(annotation.value());
                                // 如果写的名称一致，就设置值
                                if (string1.equals(string)){
                                    declaredField.set(o, declaredField1.get(t));
                                }
                            }
                        }
                    }
                }
                // 获取字段中最后一个值
                T tdata = list.get(list.size() - 1);
                Object mergeObject = field.get(tdata);
                List mergeList = Objects.nonNull(mergeObject) ? (List) mergeObject : new ArrayList<>();
                mergeList.add(o);
                // 设置合并字段的值
                field.set(t,mergeList);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * @Description 判断唯一标识，并且唯一标识的值不为空的时候，往放回结果中增加一条记录
     * @Date 11:45 2023/12/1
     * @Param [t, field]
     * @Return void
     **/
    private void onlyflagSetData(T t, Field field) {
        // 判断是否有唯一标识的注解
        GoodsExcelImportAOP onlyflag = field.getAnnotation(GoodsExcelImportAOP.class);
        if (Objects.nonNull(onlyflag)){
            try {
                Object fieldvalue = field.get(t);
                // 判断唯一标识的值不为空的时候才能添加返回数据
                if (Objects.nonNull(fieldvalue)) {
                    list.add(t);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public List<T> getList(){
        return list;
    }

    /**
     * 解析到的额外信息
     * @param extra   extra information
     * @param context analysis context
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
//        log.info("读取到了一条额外信息:{}", JSON.toJSONString(extra));
        switch (extra.getType()) {
            case COMMENT:
                log.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
                        extra.getText());
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
                            extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!A1".equals(extra.getText())) {
                    log.info(
                            "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
                                    + "内容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
                    log.error("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info(
                        "额外信息是合并单元格,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                break;
            default:
        }
    }

    /**
     * 解析完成之后调用的方法
     * @param analysisContext
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        log.info("数据解析完成");
        // 最后处理一下合并单元格的数据，把空的数据排除出去
        if (CollectionUtils.isNotEmpty(list)){
            // 循环解析出来的数据
            for (T item : list) {
                // 获取所有的字段信息
                Field[] fields = item.getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    // 判断数据是否有 合并单元格的注解
                    ExcelImportAOP excelImportAOP = field.getAnnotation(ExcelImportAOP.class);
                    if (Objects.nonNull(excelImportAOP)){
                        try {
                            List dataList = (List) field.get(item);
                            // 之后放入的合并单元格的数据不为空的时候才处理
                            if (CollectionUtils.isNotEmpty(dataList)){
                                // 获取合并单元格的迭代器，因为不符合的数据需要从list删掉
                                Iterator iterator = dataList.iterator();
                                while (iterator.hasNext()){
                                    Object datum = iterator.next();
                                    Field[] declaredFields = datum.getClass().getDeclaredFields();
                                    // 是否删除的标识
                                    boolean deleteFalge = true;
                                    for (Field declaredField : declaredFields) {
                                        declaredField.setAccessible(true);
                                        // 获取泛型数据的值
                                        Object declaredFieldValue = declaredField.get(datum);
                                        // 只要一个不为空就不删除
                                        if (Objects.nonNull(declaredFieldValue)){
                                            deleteFalge = false;
                                        }
                                    }
                                    if (deleteFalge){
                                        iterator.remove();
                                        // 判断是是否都已经删除玩了，如果都删完了，就设置为空
                                        if (CollectionUtils.isEmpty(dataList)){
                                            field.set(item,null);
                                        }
                                    }
                                }
                            }
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        }
    }
}
